<script setup lang="ts">
import { ref, provide, type Ref, computed } from 'vue';
import NdScrollContainer from '@/components/modules/NdScrollContainer.vue';
import { NdCardList, DragCardListData, DragCardData, NdCard} from '@/types/NdCard';
import CardList from './NdCardList.vue';
// 默认字段配置
const defaultFields = {
    list: {
        id: 'id',
        title: 'title',
        cards: 'cards'
    },
    card: {
        id: 'id'
    }
};
const props = withDefaults(defineProps<{
    modelValue: Array<NdCardList>;
    fields?: {
        list?: {
            id: string;
            title: string;
            cards?: string;
        };
        card?: {
            id: string;
        };
    };
}>(), {
    modelValue: () => [],
    fields: () => ({
        list: {
            id: 'id',
            title: 'title',
            cards: 'cards'
        },
        card: {
            id: 'id',
        }
    })
});
const fields = computed(() => {
    return {
        list: {
            ...defaultFields.list,
            ...props.fields?.list
        },
        card: {
            ...defaultFields.card,
            ...props.fields?.card
        }
    };
});
const emit = defineEmits<{
    (e: 'update:modelValue', cardLists: Array<NdCardList>): void,
    (e: 'cardListDragEnd', cardListId: string|number, index: number): void,
    (e: 'cardDragEnd', cardId: string|number, listId: string|number, order: number): void,
    (e: 'select', card: NdCard): void,
    (e: 'createCard', title: string, listId: string|number, callback: () => void): void
}>();
// 卡片列表元素
const cardListEls:Ref<Record<string|number, HTMLElement>> = ref({});
// 卡片元素
const cardEls:Ref<Record<string|number, HTMLElement>> = ref({});
// 拖拽卡片列表数据
const dragCardListData:Ref<DragCardListData|null> = ref(null);
// 拖拽卡片数据
const dragCardData:Ref<DragCardData|null> = ref(null);
// 计算要插入的位置
const calcCardClosestDisPos = (e: DragEvent, cardList: NdCardList) => {
    const posData = {
        index: 0
    };
    // 获取卡片数量
    const cardNums = cardList.cards.length;
    for(let i=0; i<cardNums; i++){
        const el = cardEls.value[cardList.cards[i][fields.value.card.id] as string|number];
        if(el){
            const {top, height} = el.getBoundingClientRect();
            // 计算中心点Y轴高度
            const centerY = top + height / 2;
            posData.index = i;
            if(e.clientY < centerY){
                break;
            }else if((i === cardNums - 1) && e.clientY > centerY){
                posData.index = i + 1;
            }
        }
    }
    return posData;
};
// 设置目标卡片列表
provide('setTargetCardList', (targetCardList: NdCardList) => {
    targetCardList.__activeType = 'move';
    dragCardListData.value = {
        ...dragCardListData.value,
        targetCardList,
    };
});
// 设置目标卡片
provide('setTargetCard', (targetCard: NdCard, targetCardListId: string|number) => {
    targetCard.__activeType = 'move';
    dragCardData.value = {
        ...dragCardData.value,
        targetCard,
        targetCardListId,
    };
});
// 设置目标卡片列表元素
provide('setCardListEl', (cardListId: string|number, el: HTMLElement) => {
    cardListEls.value[cardListId] = el;
});
// 设置卡片元素
provide('setCardEl', (cardId: string|number, el: HTMLElement) => {
    cardEls.value[cardId] = el;
});
const onCardListDragOver = (e: DragEvent) => {
    const { modelValue } = props;
    if (!dragCardListData.value?.targetCardList) return;
    const cardListNum = modelValue.length;
    let targetIndex = 0;
    // 计算插入位置
    for (let i = 0; i < cardListNum; i++) {
        const el = cardListEls.value[modelValue[i][fields.value.list.id] as string|number];
        if (el) {
            const { left, width } = el.getBoundingClientRect();
            const centerX = left + width / 2;
            if (e.clientX < centerX) {
                targetIndex = i;
                break;
            } else if ((i === cardListNum - 1) && e.clientX > centerX) {
                targetIndex = i + 1;
            }
        }
    }
    // 避免重复操作
    const originalIndex = modelValue.findIndex(
        item => item[fields.value.list.id] === dragCardListData.value?.targetCardList?.[fields.value.list.id]
    );
    if (originalIndex !== -1 && originalIndex !== targetIndex) {
        // 先移除旧位置
        const cardLists = props.modelValue.filter(list => list[fields.value.list.id] !== dragCardListData.value?.targetCardList?.[fields.value.list.id]);
        // 插入新位置
        cardLists.splice(targetIndex, 0, dragCardListData.value.targetCardList);
        emit('update:modelValue', cardLists);
        dragCardListData.value = {
            ...dragCardListData.value,
            targetCardListIndex: targetIndex
        };
    }
};
const onCardDragOver = (e: DragEvent, cardListId: string|number) => {
    if (!dragCardData.value?.targetCard) return;
    
    // 创建数据副本
    const cardLists = [...props.modelValue];
    const cardListIndex = cardLists.findIndex((item:NdCardList) => item[fields.value.list.id] === cardListId);
    
    if (cardListIndex === -1) return;
    
    const cardList = cardLists[cardListIndex];
    const targetCardId = dragCardData.value.targetCard[fields.value.card.id];
    
    // 从源列表中移除卡片
    if (dragCardData.value.sourceCardListId) {
        const sourceCardListIndex = cardLists.findIndex(
            (item:NdCardList) => item[fields.value.list.id] === dragCardData.value?.sourceCardListId
        );
        
        if (sourceCardListIndex !== -1) {
            cardLists[sourceCardListIndex].cards = cardLists[sourceCardListIndex].cards.filter(
                (item:NdCard) => item[fields.value.card.id] !== targetCardId
            );
        }
    }
    
    // 从当前列表中移除卡片(如果存在)
    cardList.cards = cardList.cards.filter((item:NdCard) => item[fields.value.card.id] !== targetCardId);
    
    // 更新拖拽数据
    dragCardData.value = {
        ...dragCardData.value,
        sourceCardListId: cardListId
    };
    
    // 计算插入位置并添加卡片
    const closestDisCardData = calcCardClosestDisPos(e, cardList);
    if (closestDisCardData) {
        dragCardData.value = {
            ...dragCardData.value,
            sourceCardOrder: closestDisCardData.index
        };
        
        // 在计算出的位置插入卡片
        cardList.cards.splice(closestDisCardData.index, 0, dragCardData.value.targetCard as NdCard);
        
        // 通过emit更新整体数据
        emit('update:modelValue', cardLists);
    }
};

const onCardListDragEnd = () => {
    if (dragCardListData.value?.targetCardList) {
        emit('cardListDragEnd', dragCardListData.value.targetCardList[fields.value.list.id] as string|number, dragCardListData.value.targetCardListIndex || 0);
        dragCardListData.value.targetCardList.__activeType = 'show';
        dragCardListData.value = null;
    }
};
const onCardDragEnd = () => {
    if (dragCardData.value?.targetCard) {
        dragCardData.value.targetCard.__activeType = 'show';
        emit('cardDragEnd', dragCardData.value.targetCard[fields.value.card.id] as string|number, dragCardData.value.sourceCardListId as string|number, dragCardData.value.sourceCardOrder || 0);
        dragCardData.value = null;
    }
};
const onCardSelect = (card: NdCard) => {
    emit('select', card);
};
const onCreateCard = (title: string, listId: string|number, callback: () => void) => {
    emit('createCard', title, listId, callback);
};
provide('onCardDragOver', onCardDragOver);
provide('onCardListDragEnd', onCardListDragEnd);
provide('onCardDragEnd', onCardDragEnd);
provide('onCardSelect', onCardSelect);
provide('onCreateCard', onCreateCard);
</script>

<template>
	<div 
		class="nd-card-board"
		@dragover.prevent="onCardListDragOver"
		@drop="onCardListDragEnd"
	>
		<nd-scroll-container>
			<template
				v-for="cardListObj in modelValue"
				:key="cardListObj[fields.list.id]"
			>
				<card-list
					:card-list="cardListObj"
					:fields="fields"
				>
					<template #header="{ cardList }">
						<div class="nd-card-list-title">
							{{ cardList[fields.list.title] }}
						</div>
					</template>
					<template #default="{card}">
						<slot :card="card" />
					</template>
				</card-list>
			</template>
		</nd-scroll-container>
	</div>
</template>
<style lang="scss">
@import '@/assets/scss/modules/nd-card.scss';
</style>